import asyncio
import random
import websockets
from websockets import server
from websockets import exceptions
import json
import time

connections = []
service = None
alive = True
tempRtcConnections = []


async def on_connection(webSocketServerProtocol):
    print(str(webSocketServerProtocol.remote_address) + ' on_connection')
    index = len(connections)
    item = {'id': index, 'client': webSocketServerProtocol, 'username': ''}
    connections.append(item)
    await on_message(index)


# async def on_message(webSocketServerProtocol,)

async def on_message(index):
    global alive
    while alive:
        webSocketServerProtocol = connections[index]
        client = webSocketServerProtocol['client']
        try:
            data = await client.recv()
            print(str(client.remote_address) + ' on_message')
            await deal(json.loads(data), webSocketServerProtocol)
            if data == 'close':
                alive = False
                asyncio.get_event_loop().stop()
        except exceptions.ConnectionClosedOK:

            try:
                connections.remove(webSocketServerProtocol)
                # todo 离线检测
                await client.close()
                print('connection closed')
            except ValueError:
                pass
            break
        except Exception as e:

            try:
                connections.remove(webSocketServerProtocol)
                print('connection closed')
                await client.close()
            except ValueError:
                pass
            break
        # print('sleep')
        # time.sleep(1e-3)


async def deal(data, webSocketServerProtocol):
    client = webSocketServerProtocol['client']
    print(data['type'])
    response = {}
    if data['type'] == 'login':
        protocol = findProtocolByUserName(data['username'])
        if protocol is None:
            webSocketServerProtocol['username'] = data['username']
            webSocketServerProtocol['id'] = random.randint(0, 255)
            response = {'type': 'loginResponse', 'code': 200, 'id': webSocketServerProtocol['id']}
            await client.send(json.dumps(response))
        else:
            response = {'type': 'loginResponse', 'code': 500}
            await client.send(json.dumps(response))
            await client.close()
            connections.remove(webSocketServerProtocol)

    elif data['type'] == 'initOffer':
        has_target = False
        protocol = findProtocolByUserName(data['target'])
        if protocol is None:
            response = {'type': 'initOfferResponse', 'code': 404}
        else:
            temp = {'from': data['user']['id'], 'to': protocol['id'],
                    'connectId': random.randint(500, 5000)}
            tempRtcConnections.append(temp)
            response = {'type': 'initOfferResponse', 'code': 200, 'connectId': temp['connectId']}
        await client.send(json.dumps(response))
    elif data['type'] == 'reportOffer':
        webSocketServerProtocol['offer'] = data['offer']
    elif data['type'] == 'reportOfferCandidate':
        webSocketServerProtocol['offerCandidates'].append(data['candidate'])
    elif data['type'] == 'reportAnswer':
        webSocketServerProtocol['answer'] = data['answer']
        webSocketServerProtocol['answerForId'] = data['forId']
    elif data['type'] == 'reportAnswerCandidate':
        webSocketServerProtocol['answerCandidates'].append(data['candidate'])
    elif data['type'] == 'connect':
        for temp in tempRtcConnections:
            if temp['connectId'] == data['connectId']:
                protocol = findProtocolById(temp['to'])
                if protocol is not None:
                    print(data)
                    await protocol['client'].send(json.dumps({'type': 'getOffer',
                                                              'from': webSocketServerProtocol['username'],
                                                              'connectId': temp['connectId'],
                                                              'offer': data['offer'],
                                                              'candidates': data['candidates']}))
                else:
                    response = {'type': 'connectResponse', 'code': 500}
            else:
                response = {'type': 'connectResponse', 'code': 404}
        await client.send(json.dumps(response))


def findProtocolByUserName(username):
    user = None
    for protocol in connections:
        if protocol['username'] == username:
            user = protocol
            break
    return user


def findProtocolById(userId):
    user = None
    for protocol in connections:
        if protocol['id'] == userId:
            user = protocol
            break
    return user


if __name__ == '__main__':
    run = server.serve(ws_handler=on_connection, host='0.0.0.0', port=9001)
    asyncio.get_event_loop().run_until_complete(run)
    asyncio.get_event_loop().run_forever()
